package lumis.service.wsrp.producer;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.namespace.QName;
import javax.xml.ws.Holder;

import lumis.portal.PortalException;
import lumis.portal.authentication.SessionConfig;
import lumis.portal.manager.ManagerFactory;
import lumis.portal.serviceinterfaceinstance.ServiceInterfaceInstanceConfig;
import lumis.portal.transaction.ITransaction;
import lumis.portal.transaction.PortalTransactionFactory;

import com.sun.portal.wsrp.common.stubs.v2.AccessDenied;
import com.sun.portal.wsrp.common.stubs.v2.AccessDeniedFault;
import com.sun.portal.wsrp.common.stubs.v2.Extension;
import com.sun.portal.wsrp.common.stubs.v2.InconsistentParameters;
import com.sun.portal.wsrp.common.stubs.v2.InvalidHandle;
import com.sun.portal.wsrp.common.stubs.v2.InvalidHandleFault;
import com.sun.portal.wsrp.common.stubs.v2.InvalidRegistration;
import com.sun.portal.wsrp.common.stubs.v2.InvalidUserCategory;
import com.sun.portal.wsrp.common.stubs.v2.MissingParameters;
import com.sun.portal.wsrp.common.stubs.v2.ModelDescription;
import com.sun.portal.wsrp.common.stubs.v2.OperationFailed;
import com.sun.portal.wsrp.common.stubs.v2.PortletContext;
import com.sun.portal.wsrp.common.stubs.v2.Property;
import com.sun.portal.wsrp.common.stubs.v2.PropertyDescription;
import com.sun.portal.wsrp.common.stubs.v2.PropertyList;
import com.sun.portal.wsrp.common.stubs.v2.RegistrationContext;
import com.sun.portal.wsrp.common.stubs.v2.ResetProperty;
import com.sun.portal.wsrp.common.stubs.v2.ResourceList;
import com.sun.portal.wsrp.common.stubs.v2.UserContext;
import com.sun.portal.wsrp.producer.Producer;
import com.sun.portal.wsrp.producer.ProducerException;
import com.sun.portal.wsrp.producer.WSRPProducerUtility;
import com.sun.portal.wsrp.producer.portletmanagement.PortletManagementManager;
/**
 * {@link PortletManagementManager} implementation.  Only overrides methods which implementations do not match Lumis Portal
 * domain objects.
 * 
 * <p>
 * Not all methods of PortletManagementManager interface are used for WSRP,
 * so this class just throws {@link UnsupportedOperationException} for some 
 * unused methods. 
 * </p>
 *
 * @version $Revision: 13092 $ $Date: 2011-05-28 18:19:06 -0300 (Sat, 28 May 2011) $
 * @since 6.0.0
 */
class PortletManagementManagerImpl extends com.sun.portal.wsrp.producer.portletmanagement.impl.PortletManagementManagerImpl 
{
	private static QName DEFAULT_TYPE = new QName("http://www.w3.org/2001/XMLSchema", "string", "xsd");
	/**
	 * Producer that needs to be used throughout execution
	 */
	private ProducerImpl producer;
	
	/**
	 * Only constructor receiving a Producer.
	 * @param producer to be used throughout processing.
	 * @throws ProducerException if there are any problems during its creation.
	 */
	public PortletManagementManagerImpl(Producer producer) throws ProducerException 
	{
		super(producer);
		this.producer = (ProducerImpl) producer;
	}

	@Override
	public void clonePortlet(RegistrationContext registrationContext,
			PortletContext portletContext, UserContext userContext,
			Holder<String> retportletHandle, Holder<byte[]> retportletState,
			Holder<List<Extension>> retextensions) throws InvalidHandle,
			ProducerException 
	{
		
		String rh = registrationContext.getRegistrationHandle();
        //Leasing changes
        if(!WSRPProducerUtility.isRegistrationHandleValid(producer, rh)) 
        {
            producer.setRegistrationStatus(rh, false);
            throw new ProducerException("Registration Lifetime Expired for Handle " + rh);
        }
        
        // Return the same portletHandle if clone is not supported
        if(!producer.getPortletRegistry().isCloneSupported())
        {
            retportletHandle.value = portletContext.getPortletHandle();
            return;
        }
        
        String portletHandle = portletContext.getPortletHandle();
        
        checkChannelExists(portletHandle);
        
        String cloneChannelName = ((PortletRegistryImpl)producer.getPortletRegistry()).cloneChannel(portletHandle, rh);
        
        retportletHandle.value = cloneChannelName;
		
	}
	
	@Override
	public void destroyPortlets(RegistrationContext registrationContext,
			List<String> handles, Holder<List<Extension>> extensions)
			throws ProducerException 
	{
		String[] portletHandles = (String [])handles.toArray(new String[0]);
        String rh = registrationContext.getRegistrationHandle();
        
        //Leasing changes
        if(!WSRPProducerUtility.isRegistrationHandleValid(producer, rh)) 
        {
            producer.setRegistrationStatus(rh, false);
            throw new ProducerException("Registration Lifetime Expired for Handle "+rh);
        }
        
        // Return if clone is not supported - Nothing to destroy
        if(!producer.getPortletRegistry().isCloneSupported())
        {            
            return;
        }

        
        for (int i = 0; i < portletHandles.length; i++) 
        {
        	producer.getPortletRegistry().removeChannel(rh, portletHandles[i]);
        }
    }
	
	public void getPortletProperties(RegistrationContext registrationContext, PortletContext portletContext,
			  							UserContext userContext, List<String> nms, 
			  							Holder<List<Property>> props,
			  							Holder<List<ResetProperty>> resetProperties,
			  							Holder<List<Extension>> extensions ) throws InvalidRegistration, AccessDenied, OperationFailed, MissingParameters, InvalidHandle, InvalidUserCategory, InconsistentParameters, ProducerException 
	{
	        
		String portletHandle = portletContext.getPortletHandle();
		if(registrationContext != null)
		{
			String rh = registrationContext.getRegistrationHandle();
			
			if(!WSRPProducerUtility.isRegistrationHandleValid(producer, rh)) 
			{
				producer.setRegistrationStatus(rh, false);
				throw new AccessDenied("Registration Lifetime Expired for Handle " + rh, new AccessDeniedFault());
			}
		}
		
		checkChannelExists(portletHandle);
		
		ITransaction transaction = PortalTransactionFactory.createTransaction();
		SessionConfig sessionConfig = SessionConfig.getCurrentSessionConfig();
		Map<String, String> customProperties = new HashMap<String, String>();
		try
		{
			try
			{
				transaction.begin();
				customProperties.putAll(ManagerFactory.getServiceInterfaceInstanceManager().getCustomProperties(sessionConfig, portletHandle, transaction));
				transaction.commit();
			} 
			catch (Exception e) 
			{
				throw new ProducerException(e);
			}
			finally
			{
				transaction.dispose();
			}
		}
		catch (PortalException e)
		{
			throw new ProducerException(e.getMessage(), e) ;
		}
		
		
		Set<com.sun.portal.wsrp.common.stubs.v2.Property> properties = new HashSet<Property>();
		for (String propertyName : customProperties.keySet()) 
		{
			Property property = new Property();
			property.setName(QName.valueOf(propertyName));
			property.setStringValue(customProperties.get(propertyName));
			properties.add(property);
		}
		
		
		props.value = new ArrayList<Property>();
		props.value.addAll(properties);
	}
	
	@Override
	public void setPortletProperties(RegistrationContext registrationContext,
			PortletContext portletContext, UserContext userContext,
			PropertyList propertyList, Holder<String> retportletHandle,
			Holder<byte[]> portletState, Holder<List<Extension>> extensions)
			throws MissingParameters, InvalidRegistration, InvalidUserCategory,
			OperationFailed, AccessDenied, InconsistentParameters,
			InvalidHandle, ProducerException 
	{

		
		String rh = registrationContext.getRegistrationHandle();
		String portletHandle = portletContext.getPortletHandle();
		
		if(!WSRPProducerUtility.isRegistrationHandleValid(producer, rh)) 
		{
			producer.setRegistrationStatus(rh, false);
			throw new AccessDenied("Registration Lifetime Expired for Handle " + rh, new AccessDeniedFault());
		}
		
		checkChannelExists(portletHandle);
		
		producer.getPortletRegistry().setPortletProperties( userContext, propertyList, portletHandle, rh);		
		
	}
	
	@Override
	public void getPortletPropertyDescription(
			RegistrationContext registrationContext,
			PortletContext portletContext, UserContext userContext,
			List<String> desiredLocales,
			Holder<ModelDescription> modelDescription,
			Holder<ResourceList> resourceList,
			Holder<List<Extension>> extensions) throws OperationFailed,
			MissingParameters, InvalidUserCategory, InconsistentParameters,
			AccessDenied, InvalidHandle, InvalidRegistration, ProducerException 
	{
		
		String rh = registrationContext.getRegistrationHandle();
		String portletHandle = portletContext.getPortletHandle();
		    
		if(!WSRPProducerUtility.isRegistrationHandleValid(producer, rh)) 
		{
			producer.setRegistrationStatus(rh, false);
			throw new AccessDenied("Registration Lifetime Expired for Handle " + rh, new AccessDeniedFault());
		}
		
		checkChannelExists(portletHandle);
		
		
		ITransaction transaction = PortalTransactionFactory.createTransaction();
		SessionConfig sessionConfig = SessionConfig.getCurrentSessionConfig();
		Map<String, String> customProperties = new HashMap<String, String>();
		try
		{
			try
			{
				transaction.begin();
				customProperties.putAll(ManagerFactory.getServiceInterfaceInstanceManager().getCustomProperties(sessionConfig, portletHandle, transaction));
				transaction.commit();
			} 
			catch (Exception e) 
			{
				throw new ProducerException(e);
			}
			finally
			{
				transaction.dispose();
			}
		}
		catch (PortalException e)
		{
			throw new ProducerException(e.getMessage(), e) ;
		}
		
		
		ModelDescription md = new ModelDescription();
		List<PropertyDescription> propertyDescriptions = md.getPropertyDescriptions(); 
		for (String propertyName : customProperties.keySet()) 
		{
			PropertyDescription description = new PropertyDescription();
			
			description.setName(new QName(propertyName));
			description.setType(DEFAULT_TYPE);
			
			propertyDescriptions.add(description);
		}
		
		ResourceList rl = getResourceList();
		
		modelDescription.value = md;
		resourceList.value = rl;
		
	}
	
	/**
	 * Checks if a portlet exists, either as an offeredPortlet or as a clonedPortlet.
	 * @param portletHandle handle of either OfferedPortlet or ClonedPortlet.
	 * @throws InvalidHandle if the portletHandle is invalid.
	 * @throws ProducerException if problems occur during processing.
	 */
	private void checkChannelExists(String portletHandle) throws InvalidHandle, ProducerException 
	{

		ITransaction transaction = PortalTransactionFactory.createTransaction();
		SessionConfig sessionConfig = SessionConfig.getCurrentSessionConfig();
		try
		{
			try
			{
				transaction.begin();
				
				ServiceInterfaceInstanceConfig serviceInterfaceInstanceConfig = ManagerFactory.getServiceInterfaceInstanceManager().get(sessionConfig, portletHandle, transaction);
				if(serviceInterfaceInstanceConfig == null)
				{
					throw new InvalidHandle("Invalid Portlet Handle: " + portletHandle, new InvalidHandleFault());
				}
				
				Set<String> offeredPortletNames = this.producer.getOfferedPortletNames();
				if(!offeredPortletNames.contains(portletHandle))
				{
					ClonedPortlet clonedPortlet = ManagerFactory.getEntityManager().find(ClonedPortlet.class, portletHandle);
					if(clonedPortlet == null)
					{
						throw new InvalidHandle("Invalid Portlet Handle: " + portletHandle, new InvalidHandleFault());	
					}
				}
				
				transaction.commit();
			} 
			catch (Exception e) 
			{
				throw new ProducerException(e);
			}
			finally
			{
				transaction.dispose();
			}
		}
		catch (PortalException e)
		{
			throw new ProducerException(e.getMessage(), e) ;
		}
	}
}
